package io.fatmore.web.interceptor;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
import io.fatmore.web.annotation.Api;
import io.fatmore.web.annotation.ApiWiki;
import io.fatmore.web.annotation.SessionRequire;
import io.fatmore.web.api.ApiController;
import io.fatmore.web.api.ApiException;
import io.fatmore.web.api.ApiResponse;
import io.fatmore.web.api.ApiResponseCode;
import io.fatmore.web.util.JsonUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 
 * <b><code>ApiInterceptor</code></b>
 * <p>
 * api请求的拦截，赋值
 * </p>
 * <b>Creation Time:</b> 2016年9月12日 下午10:04:50
 * @author shangkun.lsk@fastmor.com
 * @since ucun-finance
 */
public class ApiInterceptor extends HandlerInterceptorAdapter {
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		if (handler instanceof DefaultServletHttpRequestHandler) {
			return true;
		}

		if(!(handler instanceof HandlerMethod)) {
			return true;
		}

		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();

		String json = "{}" ;

		String usage = request.getParameter("$usage");
		if(usage != null && "say_fatmore_is_my_hero".equals(usage)){//TODO usage 应该做成配置
			
			this.showWiki(method,response);
			return false;
		}
		
		if (method.isAnnotationPresent(Api.class)) {
			Api annotation = method.getAnnotation(Api.class);
				String httpMethod = request.getMethod().toLowerCase();
				boolean isGet = false;
				boolean isPost = false;
				if("get".equals(httpMethod)) {
					isGet = true;
				}
				if("post".equals(httpMethod)) {
					isPost = true;
				}
				
			if (annotation != null) {
				ApiController controller = (ApiController) handlerMethod.getBean();
				if(isGet) {
					try{
						controller.validApi(request,null);
					}catch(ApiException e){
						response.getWriter().write(JsonUtil.toJson(ApiResponse.authenticateFail(e.getMessage())));
						return false;
					}
				} else if (isPost && request instanceof ApiRequestWrapper) {
					ApiRequestWrapper apiRequest = (ApiRequestWrapper) request;
					json = apiRequest.getBody();
					try{
						controller.validApi(request,json);
					}catch(ApiException e){
						response.getWriter().write(JsonUtil.toJson(ApiResponse.authenticateFail(e.getMessage())));
						return false;
					}
				}
			} else {
				return true;
			}
		}
		
		if(method.isAnnotationPresent(SessionRequire.class)){
			SessionRequire sa = method.getAnnotation(SessionRequire.class);
			if(sa != null){
				ApiController controller = (ApiController) handlerMethod.getBean();
				controller.initSession(request, json);
				if(!controller.hasSession()){
					ApiResponse res = ApiResponse.error("请登录").setCode(
							ApiResponseCode.not_login);
					response.getWriter().write(JsonUtil.toJson(res));
					return false;
				}
				
			}
		}
		return true;
	}
	
	/**
	 * @author shangkun.lsk@fastmor.com
	 * 
	 *
	 * @param method
	 * @param response
	 * @since ucun_material 
	 * @warn dont copy!
	 */
	private void showWiki(Method method, HttpServletResponse response){
		Map<String,Object> json  = new LinkedHashMap<>();
		Class clz = method.getDeclaringClass();
		json.put("class", clz.getName());
		
		Annotation caw_ = clz.getAnnotation(ApiWiki.class);
		if(caw_ != null){
			ApiWiki caw = (ApiWiki) caw_;
			json.put("class.alias", caw.alias());
			json.put("class.wiki", caw.wiki());
		}

		json.put("method", method.getName());
		
		//请求地址就不输出了，都已经请求进来了
		ApiWiki maw = method.getAnnotation(ApiWiki.class);
		if(maw != null){
			json.put("method.alias", maw.alias());
			json.put("method.wiki", maw.wiki());
		}else{
			json.put("method.wiki", "开发人员太懒了，连wiki都没写");
		}
		
		//探测形参
		Parameter[] params=method.getParameters();
		int pc = 0;
		for(Parameter par:params){
			String p = "arg"+pc;
			json.put(p+".Type", par.getType()+"");
			ApiWiki paw = par.getType().getAnnotation(ApiWiki.class);
			if(paw != null){
				json.put(p+".alias", paw.alias());
				json.put(p+".wiki", paw.wiki());
			}

			RequestBody rb = par.getAnnotation(RequestBody.class);
			if(rb != null){
				//实例化				
				try {
						//TODO 再这些request body上支持apiWiki的属性，输出完整的提示
						Object obj = par.getType().newInstance();//这句拿内部类没办法
						json.put(p+".body", obj);

				} catch (Exception e) {
					e.printStackTrace();
					json.put(p+".error_when_learn_body_wiki", e.getMessage());
					json.put(p+".tips", "尚未支持memberClass, localClass,anonymousClass等，敬请期待 ");
				}
				
			}
			
            pc ++;
        }
		
		
		
		try {
			response.getWriter().write(JsonUtil.formatJson(json));
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
	
	

}
